package com.ruoyi.project.utils;

import cn.hutool.core.util.NumberUtil;
import org.apache.commons.lang3.StringUtils;

import java.math.BigDecimal;
import java.util.Arrays;

/**
 * 数字工具类
 *
 * @author 挺好的 2023年02月10日 10:32
 */
public final class NumberUtils {

    /**
     * 单位
     */
    private static final String[] NUMBER_SUFFIX = new String[] {"千", "万", "亿", "", "", "", "", "", "", "", "", "", "", "", "", ""};


    private NumberUtils () {
    }

    /**
     * 数字相减
     *
     * @param end
     *         减数
     * @param begin
     *         被减数
     *
     * @return
     */
    public static Long subtract (Long end, Long begin) {

        if (end == null || begin == null) {
            return 0L;
        }

        return end - begin;
    }

    /**
     * 将阿拉伯数字转化为简介计数单位，例如 2100 =》 2.1千
     *
     * @param decimal
     *         对应数字的值
     *
     * @return 格式化后的数字
     */
    public static String numberToSimple (BigDecimal decimal) {
        return numberToSimple(decimal.longValue(), "#.##");
    }

    /**
     * 将阿拉伯数字转化为简介计数单位，例如 2100 =》 2.1千
     *
     * @param value
     *         对应数字的值
     *
     * @return 格式化后的数字
     */
    public static String numberToSimple (Long value, String format) {

        if (StringUtils.isEmpty(format)) {
            format = "#.##";
        }

        // 如果为空，则返回0
        if (value == null) {
            return "0";
        }

        if (value < 1000) {
            return String.valueOf(value);
        }
        int index = -1;
        double res = value;
        while (res > 10 && (index < 1)) {
            // 得到千
            if (res > 1000) {
                res = res / 1000;
                index++;
            }
            // 得到万
            if (res > 10) {
                res = res / 10;
                index++;
            }

            // 得到亿，
            if (res >= 10000) {
                res = res / 10000;
                index++;
            }
        }
        return String.format("%s%s", NumberUtil.decimalFormat(format, res), NUMBER_SUFFIX[index]);
    }

    /**
     * 判断给定整数是否是正数
     *
     * @param value
     *         整数
     * @param isStrictly
     *         是否是严格模式，如果是， 0将被视为无效值。
     *
     * @return
     */
    public static boolean isPositive (Integer value, boolean isStrictly) {

        if (value == null) {
            return false;
        }

        int signum = Integer.signum(value);

        return isStrictly ? signum > 0 : signum >= 0;
    }

    /**
     * 判断给定整数是否是正数
     *
     * @param value
     *         整数
     *
     * @return 如果value == null，返回false。否则返回指定int值的signum函数。 （如果指定的值为负，则返回值为-1；如果指定的值为零，则返回0；如果指定的值为正，则返回1。
     */
    public static boolean isPositive (Integer value) {
        return isPositive(value, true);
    }

    /**
     * 判断给定整数是否是正数
     *
     * @param value
     *         整数
     *
     * @return 如果value == null，返回false。否则返回指定int值的signum函数。 （如果指定的值为负，则返回值为-1；如果指定的值为零，则返回0；如果指定的值为正，则返回1。
     */
    public static boolean isPositive (Long value) {

        if (value == null) {
            return false;
        }

        return Long.signum(value) > 0;
    }

    /**
     * 是否是double
     *
     * @param value
     *         值
     *
     * @return 如果value == null，返回false. 如果value > 0 返回true
     */
    public static boolean isPositive (Double value) {
        if (value == null) {
            return false;
        }

        return value > 0;
    }

    /**
     * 转换为int
     *
     * @param value
     *         值
     * @param defaultValue
     *         默认值
     *
     * @return 当值为空时，返回的默认值
     */
    public static Integer toInteger (Integer value, Integer defaultValue) {

        if (value == null) {
            return defaultValue;
        }
        return value;
    }

    /**
     * 转换为long
     *
     * @param value
     *         值
     * @param defaultValue
     *         默认值
     *
     * @return 当值为空时，返回的默认值
     */
    public static Long toLong (Long value, Long defaultValue) {
        if (value == null) {
            return defaultValue;
        }

        return value;
    }

    /**
     * 转换double，
     *
     * @param value
     *         值， value
     * @param defaultValue
     *         默认值
     *
     * @return
     */
    public static Double defaultDouble (Double value, double defaultValue) {
        if (value == null) {
            return defaultValue;
        }

        return value;
    }

    /**
     * 转换为long，如果value 为 空，返回defaultValue
     *
     * @param value
     *         值， value
     * @param defaultValue
     *         默认值
     *
     * @return
     */
    public static Long defaultLong (Long value, long defaultValue) {
        if (value == null) {
            return defaultValue;
        }

        return value;
    }

    /**
     * 转换为long， defaultValue 为 0
     *
     * @param value
     *         值
     *
     * @return
     */
    public static Long defaultLong (Long value) {
        return defaultLong(value, 0L);
    }

    /**
     * list 求和
     *
     * @param values
     *
     * @return
     */
    public static Long sum (Long... values) {
        return Arrays.stream(values).mapToLong(NumberUtils::defaultLong).sum();
    }

    /**
     * 字符串转换为数字
     *
     * @param value
     *         字符串
     *
     * @return 转换后的数字，无法转换或者字符串为空，返回0
     */
    public static Long convertToLong (String value) {
        return convertToLong(value, 0L);
    }

    /**
     * 字符串转换为数字
     *
     * @param value
     *         字符串
     * @param defaultValue
     *         默认值
     *
     * @return 转换后的数字，无法转换或者字符串为空，返回默认值
     */
    public static long convertToLong (String value, long defaultValue) {

        if (StringUtils.isEmpty(value)) {
            return defaultValue;
        }

        try {
            return Long.parseLong(value);
        } catch (Exception e) {
            return defaultValue;
        }
    }

    public static int convertToInt (String value, int defaultValue) {
        if (StringUtils.isEmpty(value)) {
            return defaultValue;
        }

        try {
            return Integer.parseInt(value);
        } catch (Exception e) {
            return defaultValue;
        }
    }

    /**
     * 两个长整型数字是否相等
     *
     * @param source
     *         源
     * @param target
     *         目标
     *
     * @return source == null || target == null，return false。 如果source和target分别在LongCache中，使用==比较，否则使用equals比较
     */
    public static boolean equals (Long source, Long target) {

        if (source == null || target == null) {
            return false;
        }

        if (source == target) {
            return true;
        }

        return source.equals(target);
    }

    /**
     * 两个整型数字是否相等
     *
     * @param source
     *         源
     * @param target
     *         目标
     *
     * @return source == null || target == null，return false。 如果source和target分别在IntegerCache中，使用==比较，否则使用equals比较
     */
    public static boolean equals (Integer source, Integer target) {
        if (source == null || target == null) {
            return false;
        }

        if (source == target) {
            return true;
        }

        return source.equals(target);
    }

    /**
     * source > target
     *
     * @param source
     *         源数据
     * @param target
     *         目标数据
     *
     * @return source 是否大于 target
     */
    public static boolean isGt (Integer source, Integer target) {
        if (source == null || target == null) {
            return false;
        }

        return Integer.signum(source - target) > 0;
    }

    /**
     * source >= target
     *
     * @param source
     *         源数据
     * @param target
     *         目标数据
     *
     * @return source 是否大于等于 target
     */
    public static boolean isGe (Integer source, Integer target) {
        if (source == null || target == null) {
            return false;
        }

        return Integer.signum(source - target) >= 0;
    }

    /**
     * 是否小于0
     *
     * @param source
     *         原数据
     *
     * @return 如果source == null, 返回true
     */
    public static boolean isLessThanZero (BigDecimal source) {
        if (source == null) {
            return true;
        }

        return source.compareTo(BigDecimal.ZERO) < 0;
    }

    /**
     * 是否小于等于0
     *
     * @param source
     *         原数据
     *
     * @return 如果source == null, 返回true
     */
    public static boolean isLessOrEqualsZero (BigDecimal source) {

        if (source == null) {
            return true;
        }

        return source.compareTo(BigDecimal.ZERO) <= 0;
    }

    /**
     * source是否大于target
     *
     * @param source
     *         原数据
     * @param target
     *         目标数据
     *
     * @return source == null || target == null，返回false
     */
    public static boolean isGt (BigDecimal source, BigDecimal target) {
        if (source == null || target == null) {
            return false;
        }

        return source.compareTo(target) > 0;
    }

    /**
     * source是否大于target
     *
     * @param source
     *         原数据
     *
     * @return source == null || target == null，返回false
     */
    public static boolean isGtZero (BigDecimal source) {
        if (source == null) {
            return false;
        }
        return source.compareTo(BigDecimal.ZERO) > 0;
    }

    /**
     * 是否是0
     *
     * @param source
     *         source == null ，也被认为是0,
     *
     * @return source == null || source == 0 ，返回true
     */
    public static boolean isZero (BigDecimal source) {
        if (source == null) {
            return true;
        }

        return source.compareTo(BigDecimal.ZERO) == 0;
    }

    /**
     * source 是否小于 target
     *
     * @param source
     *         源数字
     * @param target
     *         目标数字
     *
     * @return source || target is null, return true
     */
    public static boolean isLess (BigDecimal source, BigDecimal target) {

        if (source == null || target == null) {
            return true;
        }

        return source.compareTo(target) < 0;
    }

    /**
     * 高精度浮点型，保留两位小数。四舍五入
     *
     * @param value
     *         转换的值
     *
     * @return 如果value == null ，返回0
     */
    public static BigDecimal setScale (BigDecimal value) {
        return setScale(value, BigDecimal.ROUND_HALF_UP);
    }

    /**
     * 高精度浮点型，保留两位小数
     *
     * @param value
     *         转换的值
     * @param roundingMode
     *         小数保留模式
     *
     * @return 如果value == null ，返回0
     */
    public static BigDecimal setScale (BigDecimal value, int roundingMode) {
        if (value != null) {
            return value.setScale(2, roundingMode);
        } else {
            return BigDecimal.ZERO;
        }
    }

    /**
     * 保留两位小数
     *
     * @param value
     *
     * @return
     */
    public static Double setScale (Double value) {

        if (value == null) {
            return 0D;
        }

        return setScale(BigDecimal.valueOf(value)).doubleValue();
    }

    /**
     * 分转换为元
     *
     * @param fee
     *         待转换的金额， 单位分
     *
     * @return
     */
    public static BigDecimal fenToYuan (Long fee) {
        if (fee == null || fee == 0L) {
            return BigDecimal.ZERO;
        }

        // 分 / 100
        BigDecimal yuan = new BigDecimal(fee).divide(BigDecimal.TEN).divide(BigDecimal.TEN);

        return setScale(yuan);
    }

    /**
     * 分转换为元
     *
     * @param fee
     *         待转换的金额， 单位分
     *
     * @return
     */
    public static BigDecimal fenToYuan (String fee) {
        Long longFee = convertToLong(fee, 0L);
        return fenToYuan(longFee);
    }
}
